--extend UserData

local UserData = import(".UserData")

local Item = import(".Item")
local Equip = import(".Equip")
local Jewel = import(".Jewel")
local Mount = import(".Mount")
local Partner = import(".Partner")
local Clothes = import(".Clothes")
local Fame = import(".Fame")
local Daibi = import(".Daibi")
local Tool = import(".Tool")
local Skill = import(".Skill")
local Talent = import(".Talent")
local MountSoul = import(".MountSoul")
local PartnerSoul = import(".PartnerSoul")
local MapBuff = import(".MapBuff")

local protobuf = require "protobuf"

local string_split = string.split


-- Enums.PropType 根据类型解析
-- 从1|71100005|1 or 1|71100005 or 1|71100005|1|10，解析出奖励
-- reward   1|71100005|1 or 1|71100005 or 1|71100005|1|10
-- split    默认是 "|"
-- return   Item/Equip/Mount/Fame/Tool/Daibi
function UserData:parseRewardToBagItem(reward, split)
    if not reward then return nil end

    local ary = string_split(reward, split or "|")
    local tp = tonumber(ary[1])
    local itemId = tonumber(ary[2])
    local amount = tonumber(ary[3] or 1) or 1
    local itemData
    if tp == 1 then
        itemData = Item.new(Enums.ItemBagType.item)
        itemData:read({tid=itemId, amount=amount})
    elseif tp == 2 or tp == 3 then
        itemData = Equip.new(true)
        itemData:read({tid=itemId})
    elseif tp == 4 then
        itemData = Mount.new()
        itemData:read({tid=itemId})
    elseif tp == 5 then
        itemData = Tool.new()
        itemData:read({tid=itemId})
    elseif tp == 8 then
        itemData = Jewel.new()
        itemData:read({tid=itemId})
        itemData:setAmount(amount)
    elseif tp == 11 then
        --随从需要支持
        itemData = Partner.new()
        itemData:initWithId(itemId)
    elseif tp == 21 then
        itemData = MapBuff.new()
        itemData:read({tid=itemId})
        itemData:setAmount(amount)
    elseif tp == 80 then
        itemData = MountSoul.new()
        itemData:read({id=itemId, num=amount})
    elseif tp == 133 then
        itemData = PartnerSoul.new()
        itemData:read({id=itemId, num=amount})
    elseif tp == 81 then
        --为fashion需要特殊处理
        itemData = Clothes.new()
        itemData:read({tid=itemId})
    elseif tp == 100 then
        itemData = Fame.new()
        itemData:read({uid=itemId, level=1, exp=0})
        itemData:setAmount(amount)
    elseif tp == 108 then -- 宝石组
        local data = GD:getResDataByJewelGroupId(itemId)
        if data then
            local tp = tonumber(data.ID)
            local coinConf = GD:getCoinConfig(tp)
            if coinConf then
                itemData = Daibi.new()
                itemData:read({tid=tp, amount=0})
                itemData:setLevel(tonumber(data.jewelLv))
            end
        end
    else
        local coinConf = GD:getCoinConfig(tp)
        if coinConf then
            itemData = Daibi.new()
            itemData:read({tid=tp, amount=amount})
        end
    end
    if itemData then
        return itemData
    else
        print("UserData:parseRewardToBagItem() not support type = ", tp)
        return nil
    end
end

-- Loot解析
-- loot    Loot结构，在shared.proto, pg_loot.proto
-- return   Item/Equip/Mount/Fame/Tool/Daibi
function UserData:parseLootToBagItem(loot)
    local tp = protobuf.enum_id("pb_loot.Loot.LootType", loot.type) or loot.type
    local itemId = loot.id
    local amount = loot.num
    local itemData
    if tp == 1 then
        itemData = Item.new(Enums.ItemBagType.item)
        itemData:read({tid=itemId, amount=amount})
    elseif tp == 2 or tp == 3 then
        itemData = Equip.new(true)
        itemData:read({tid=itemId})
    elseif tp == 4 then
        itemData = Mount.new()
        itemData:read({tid=itemId})
    elseif tp == 5 then
    elseif tp == 7 then
    elseif tp == 8 then
        itemData = Jewel.new()
        itemData:read({tid=itemId})
        itemData:setAmount(amount)
    elseif tp == 11 then
        --随从需要支持
        itemData = Partner.new()
        itemData:initWithId(itemId)
    elseif tp == 21 then
        itemData = MapBuff.new()
        itemData:read({tid=itemId})
        itemData:setAmount(amount)
    elseif tp == 80 then
        itemData = MountSoul.new()
        itemData:read({id=itemId, num=amount})
    elseif tp == 133 then
        itemData = PartnerSoul.new()
        itemData:read({id=itemId, num=amount})
    elseif tp == 81 then
        --为fashion需要特殊处理
        itemData = Clothes.new()
        itemData:read({tid=itemId})
    elseif tp == 100 then
        itemData = Fame.new()
        itemData:read({uid=itemId, level=1, exp=0})
        itemData:setAmount(amount)
    else
        local coinConf = GD:getCoinConfig(tp)
        if coinConf then
            itemData = Daibi.new()
            itemData:read({tid=tp, amount=amount})
        end
    end
    if itemData then
        return itemData
    else
        print("UserData:parseLootToBagItem() not support type = ", tp)
        return nil
    end
end

-- 解析以下格式
-- 1|71100005|1;1|71100005|1;...
function UserData:parseItemsFromString(str, classId)
    local items={}
    if str then
        str = self:parseClassText(str, classId)
        local ary = string_split(str,";")
        for i,v in ipairs(ary) do
            local item=self:parseRewardToBagItem(v)
            if item then
                table.insert(items, item)
            end
        end
    end
    return items
end

-- 解析以下格式 可能包含 Class适配
-- 1|71100005|1
function UserData:parseItemFromString(str, classId)
    str = str and self:parseClassText(str, classId)
    return self:parseRewardToBagItem(str)
end

-- classId 替换规则，处理配置表中有{{.Classes}}的情况
local CLASSID_REPLACE_DICT

-- 解析 {{.Class}} 此类结构文本 用classId替换
-- 解析 {{.Classes}} 此类结构文本 需用CLASSID_REPLACE_DICT处理过的classId替换
-- 例子
-- 1. 62999199{{.Class}} 用classId替换
-- 2. 2|7{{.Class}}20113 用classId替换
-- 3. 62999199{{.Classes}} 用CLASSID_REPLACE_DICT[classId]替换
-- 4. 2|7{{.Classes}}20113 用CLASSID_REPLACE_DICT[classId]替换
function UserData:parseClassText(str, classId)
    -- print("UserData.parseClassText str classId", str, classId)
    classId = classId or self.player.classID
    local ret = tostring(str)
    if string.find(ret, "{{.Classes}}") then
        if not CLASSID_REPLACE_DICT then
            local replaceStr = GD:getSystemStrPar("classesRelation")
            if replaceStr then
                CLASSID_REPLACE_DICT = {}
                local ary = string.splitTwice(replaceStr, nil, true)
                for i,v in ipairs(ary) do
                    CLASSID_REPLACE_DICT[v[1]] = v[2]
                end
            else
                CLASSID_REPLACE_DICT = {1,2,3,4,2}
            end
        end

        local replaceClassId = CLASSID_REPLACE_DICT[classId]
        ret = string.gsub(ret, "{{.Classes}}", replaceClassId)
    end
    if string.find(ret, "{{.Class}}") then
        ret = string.gsub(ret, "{{.Class}}", classId)
    end
    if ret then
        -- print("UserData.parseClassText succ", ret)
        return ret
    else
        print("UserData.parseClassText fail")
        return nil
    end
end

function UserData:parseDropIDToBagItem(dropId)
    local conf = GD:queryDrop(dropId)
    if conf then
        local dropStr = conf.dropGroup
        if dropStr then
            dropStr = self:parseClassText(dropStr)
            local ret = {}
            local ary = string_split(dropStr, ";")
            for _, v in ipairs(ary) do
                local itemData = self:parseRewardToBagItem(v)
                if itemData then
                    ret[#ret + 1] = itemData
                end
            end
            return ret
        end
    end
end
    
-- 从dropId解析第一个Loot(pb_loot.Loot)
function UserData:parseDropToLoot(dropId, classId)
    local conf = GD:queryDrop(dropId)
    if not conf then return end
    
    local dropStr = conf.dropGroup
    if not dropStr then return end
    
    dropStr = self:parseClassText(dropStr, classId)
    local ary = string_split(dropStr, ";")
    if not ary[1] then return end
    
    ary = string_split(ary[1], "|")

    local loot = {}
    loot.type = protobuf.enum_name("pb_loot.Loot.LootType", tonumber(ary[1]))
    loot.id = tonumber(ary[2])
    loot.num = tonumber(ary[3])

    return loot
end

-- 从dropId 获取可以获得的奖励，可能解析失败
-- param dropId
-- param isFirst 是否只取第一个group的第一个数据
-- return {{itemData,..}, {itemData,..}, ..}
-- itemData = Item/Equip/Mount/Fame/Tool/Daibi
function UserData:parseDropToBagItem(dropId, isOnlyFirst, classId)
    -- print("UserData.parseDropToBagItem dropId isOnlyFirst", dropId, isOnlyFirst)
    local conf = GD:queryDrop(dropId)
    local ret = nil
    if conf then
        ret = {}
        local dropStr = conf.dropGroup
        if dropStr then
            dropStr = self:parseClassText(dropStr, classId)
            local ary = string_split(dropStr, ";")
            for _, v in ipairs(ary) do
                local itemData = self:parseRewardToBagItem(v)
                if itemData then
                    ret[#ret + 1] = itemData
                end
            end
        end
    end

    --dump(ret, "UserData.parseDropToBagItem ret", 10)

    if isOnlyFirst then
        if ret then
            return ret[1]
        else
            return nil
        end
    else
        return ret
    end
end

-- 从 dropStr 获取可以获得的奖励
-- dropStr 910200101;910200301 dropId组
function UserData:parseDropStrToBagItem(dropStr, isOnlyFirst, classId)
    dropStr = self:parseClassText(dropStr, classId)
    local ary = string_split(dropStr, ";")
    local ret = {}
    for _,dropId in ipairs(ary) do
        local items = self:parseDropToBagItem(dropId, isOnlyFirst, classId)
        if items then
            if isOnlyFirst then
                table.insert(ret, items)
            else
                ret = table.attach(ret, items)
            end
        end
    end
    return ret
end

-- 从战斗配置中解析出技能消耗，CD相关参数
function UserData:getSkillCost(skillId, lv)
    local mana, rage, energy, cd, combopoint = 0, 0, 0, 0
    if skillId>0 and battle then
        local battleConfig = battle.BattleConfig:getInstance()
        if battleConfig then
            local skillConfig = battleConfig:getSkillConfig(skillId)
            if skillConfig then
                mana = math.modf(skillConfig:getManaCost(lv) / 100)
                rage = math.modf(skillConfig:getRageCost(lv) / 100)
                energy = math.modf(skillConfig:getEnergyCost(lv) / 100)
                cd = skillConfig:getCdD(lv)
                
                local isLock = skillConfig:getConsumeAllComboPoint(lv)
                if not isLock then
                    combopoint = skillConfig:getComboPointCost(lv)
                else
                    local consumeComboPointMax = skillConfig:getConsumeComboPointMax(lv)
                    if consumeComboPointMax == 0 then
                        consumeComboPointMax = Constant.BattleComboPointMax
                    end
                    combopoint = consumeComboPointMax
                end
            end
        end
    end

    return mana, rage, energy, cd, combopoint
end
